package fightplan.algorithmen.ko;

import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

import com.jgoodies.binding.value.AbstractValueModel;

import fightplan.business.AbstractFighter;
import fightplan.business.Fight;
import fightplan.business.FighterHolder;
import fightplan.business.FighterProvider;
import fightplan.business.ModifiableFighterProvider;
import fightplan.business.Result;
import fightplan.core.Util;

public class TrostRunde implements PropertyChangeListener, Serializable {
	private static final long serialVersionUID = 1L;

	private Fight rootFight;
	private List<TrostRundenFighterProvider> loosers;
	private List<FighterHolder> winners; // Holders of fight winners

	public TrostRunde(Fight rootFight) {
		this.rootFight = rootFight;
		this.loosers = new ArrayList<TrostRundenFighterProvider>();
		this.winners = new ArrayList<FighterHolder>();
		update();
	}

	/**
	 * @param level
	 *            0 = letzter Kämpfer, der gegen Finalist verloren hat. 1 =
	 *            vorletzter usw.
	 * @return FighterHolder
	 */
	public TrostRundenFighterProvider getLooser(int level) {
		while (level >= loosers.size()) {
			loosers.add(new TrostRundenFighterProvider());
		}
		return loosers.get(level);
	}

	// PropertyChangeListener

	public void propertyChange(PropertyChangeEvent evt) {
		update();
	}

	private synchronized void update() {
		// remove old listeners
		for (FighterHolder winner : winners) {
			winner.removePersistentChangeListener(this);
		}
		winners.clear();

		Fight prevFight = rootFight;
		int level = 0;
		while (prevFight != null) {
			Fight fight = prevFight;
			prevFight = null;

			winners.add(fight.getWinResultHolder());
			fight.getWinResultHolder().addPersistentChangeListener(this);

			if (fight.getFightEntries().get(0).getFighterProvider().getFighter() != null
					&& fight.getFightEntries().get(1).getFighterProvider().getFighter() != null) {

				FighterProvider winnerProvider = null;
				AbstractFighter looser = null;

				if (Result.WON.equals(fight.getFightEntries().get(0).getResult())) {
					winnerProvider = fight.getFightEntries().get(0).getFighterProvider();
					looser = fight.getFightEntries().get(1).getFighterProvider().getFighter();
				} else if (Result.WON.equals(fight.getFightEntries().get(1).getResult())) {
					winnerProvider = fight.getFightEntries().get(1).getFighterProvider();
					looser = fight.getFightEntries().get(0).getFighterProvider().getFighter();
				}

				if (looser != null) {
					TrostRundenFighterProvider looserProvider = getLooser(level);
					looserProvider.setFighter(looser);

					if (winnerProvider instanceof FighterHolder) {
						prevFight = ((FighterHolder) winnerProvider).getFight();
					}
				}

			}
			level = level + 1;
		}
		while (level < loosers.size()) {
			loosers.get(level).setFighter(null);
			level = level + 1;
		}
	}

	public class TrostRundenFighterProvider extends AbstractValueModel implements ModifiableFighterProvider {
		private static final long serialVersionUID = 1L;

		private PropertyChangeSupport persistentChangeListeners;

		private AbstractFighter fighter = null;

		public TrostRundenFighterProvider() {
		}

		public Object getValue() {
			return fighter;
		}

		public AbstractFighter getFighter() {
			return fighter;
		}

		public void setValue(Object newValue) {
			AbstractFighter newFighter = (AbstractFighter) newValue;
			AbstractFighter oldFighter = getFighter();
			if (Util.equals(oldFighter, newValue))
				return;
			fighter = newFighter;
			fireValueChange(oldFighter, newFighter, true); // check identity
			if (persistentChangeListeners != null) {
				persistentChangeListeners.firePropertyChange(PROPERTYNAME_VALUE, oldFighter, newFighter);
			}
		}

		public void setFighter(AbstractFighter fighter) {
			setValue(fighter);
		}

		public void addPersistentChangeListener(PropertyChangeListener listener) {
			if (persistentChangeListeners == null) {
				persistentChangeListeners = new PropertyChangeSupport(this);
			}
			persistentChangeListeners.addPropertyChangeListener(listener);
		}

		public void removePersistentChangeListener(PropertyChangeListener listener) {
			if (persistentChangeListeners != null) {
				persistentChangeListeners.removePropertyChangeListener(listener);
			}
		}

	}

}